/*!
 * vinculum
 * Copyright(c) 2017 azzly
 * MIT Licensed
 */
 
'use strict';

/**
 * Module dependencies.
 * @private
 */
const express = require("express");
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const path = require('path');
const fs = require('fs');

const CONST = require("./lib/CONST");
const config = require("./lib/config");
const helper = require("./lib/helper");
const cache = require("./lib/cache");
const debug = require("./lib/debug")(__filename);
const datasource = require("./lib/datasource");
const utils = require("./lib/utils");
const request = require("./lib/request");
const response = require("./lib/response");
const session = require("./lib/session");
const auth_router = require('./lib/router/auth');
const service_router = require('./lib/router/service');
const action_router = require('./lib/router/action');
const application_router = require('./lib/router/application');
const clear_router = require('./lib/router/clear');
const login_router = require('./lib/router/login');
const cron_router = require('./lib/router/cron');

/**
 * Variable.
 * @private
 */

const libs = [
	'css/console.css'
	,'css/login.css'
	,'js/login.js'
	,'js/console.js'
	,'js/vinculum.js'
	,'js/theme/components_amazeui.js'
	,'js/theme/components_bootstrap.js'
];

const rootPath = __dirname + '/lib/templates/';

const outPath = __dirname + '/public/';

const sessionExpire = 1000 * 60 * 60 * 24 * 365 * 20;
/**
 * prototype.
 */

let obj = exports = module.exports = {};

/**
 * md5
 *
 * @public
 */
 
obj.md5 = function(a){
	return helper.md5(a);
};

/**
 * set
 *
 * @public
 */
 
obj.set = function(key,value){
	debug(`set ${key}, ${value}`);
  config[key] = value;
};

/**
 * start
 *
 * @public
 */
 
obj.start = function(port = 80){
	datasource.init(config.serverdb);
	const app = express();
	
	app.disable('x-powered-by');
	app.set('env','production');
	app.set('case sensitive routing',true);
	app.use(bodyParser.urlencoded({ 
		extended: true
		,parameterLimit:50
		,limit:'50kb'
	}));
	app.use(cookieParser());
	
	debug('create system tables...');
	obj.createSystemTables().then(result=>{
		debug('create system tables success');
		debug('init cache...');
		return obj.initCache();
	}).then(result=>{
		debug('init cache success');
		debug('upgrade system...');
		return obj.upgradeSystem();
	}).then(result=>{
		debug('upgrade system success');
		debug('init datasources...');
		return obj.initDataSources();
	}).then(result=>{
		for(let one of result){
			datasource.setDB(one.id,one);
		}
		debug('init datasources success');
		debug('init minify...');
		return obj.initMinify();
	}).then(result=>{
		debug('init minify success');
		const path = config.context || "";
		app.use(`/${path}`,obj.getRouter());
		app.listen(port);
		debug('start server with port: ' + port);
	}).catch(err=>{
		console.error(err);
		process.exit(1);
	});
	return app;
};

/**
 * createSystemTables
 *
 * @public
 */
 
obj.createSystemTables = function(){
  const tables = require('./lib/tables');
	const keys = Object.keys(tables);
	var promises = keys.map(function (key) {
		return datasource.systemQuery(tables[key].createSql(),null);
	});
	return Promise.all(promises);
};

/**
 * upgradeSystem
 *
 * @public
 */
 
obj.upgradeSystem = function(){
  return Promise.resolve();
};

/**
 * initMinify
 *
 * @public
 */
 
obj.initMinify = function(){
	let newLibs = libs.map(function(one){
		let srcPath = rootPath + one;
		let outPath2 = outPath + one;
		let srcPathObj = path.parse(srcPath);
		let outPathObj = path.parse(outPath2);
		return {
			content: fs.readFileSync(srcPath,'utf8')
			,ext: srcPathObj.ext
			,outPath: outPath2
			,outDir: outPathObj.dir
		};
	});
  return new Promise((resolve, reject)=>{
		obj.babelLessMinify(newLibs,err=>{
			resolve();
		});
	});
};

/**
 * babelLessMinify
 *
 * @public
 */
 
obj.babelLessMinify = function(arr,callback){
  helper.async(arr,obj.babelLessMinifyOne,callback);
};

/**
 * babelLessMinifyOne
 *
 * @public
 */
 
obj.babelLessMinifyOne = function(one,cb){
	let method;
	if(one.ext === '.js'){
		method = 'babel_js';
	}else if(one.ext === '.css'){
		method = 'less_css';
	}
	
	if(method){
		utils[method](one.content,true,function(err,code){
			if(!err){
				helper.mkdirs(one.outDir);
				fs.writeFileSync(one.outPath,code,'utf8');
			}
			cb(err);
		});
	}else{
		cb(null);
	}
};

/**
 * initDataSources
 *
 * @public
 */
 
obj.initDataSources = function(){
  return datasource.systemQuery(CONST.SQLS.datasource_list,null);
};

/**
 * initCache
 *
 * @public
 */
 
obj.initCache = function(){
  return new Promise((resolve, reject)=>{
		if(config.sessionCache === CONST.SESSION_CACHE_TYPE.REDIS){
			cache.initRedis(config.redisOptions,function(err){
				if(err){
					reject(err);
				}else{
					resolve();
				}
			});
		}else{
			resolve();
		}
	});
};

/**
 * getRouter
 *
 * @public
 */
 
obj.getRouter = function(){
  const router = express.Router();
			
	router.use((req,res,next)=>{
		req.vinculum = new request(req);
		res.vinculum = new response(res);
		let sessionKey = req.cookies[config.cookieName];
		if(!sessionKey){
      sessionKey = helper.uuid();
      res.cookie(config.cookieName,sessionKey,{
				httpOnly:true
				,expires: new Date(Date.now() + sessionExpire)
				,maxAge:sessionExpire
			});
    }
		const asession = new session(sessionKey);
		req.vinculum.session = res.vinculum.session = asession;
		asession.init().then(()=>{
			debug(`init session success`);
      req.vinculum.sessionToParams();
      next();
    }).catch(err=>{
			debug(`init session fail ${err}`);
      res.vinculum.error(err);
    });
	});
	
	// 权限路由
	router.get('/:type',auth_router());
	router.get('/:type/:id',auth_router());
	router.post('/:type',auth_router());
	router.post('/:type/:id',auth_router());	
	
	// 服务路由
	router.get('/service/:id',service_router());
	router.post('/service/:id',service_router());	
	
	// 动作路由
	router.get('/action/:id',action_router());
	router.post('/action/:id',action_router());	
	
	// 应用路由
	router.get('/application/:id',application_router());
	
	// 资源路由
	router.use('/resource', express.static(__dirname + '/public'));
	
	// 清空缓存
	router.get('/clearCache',clear_router());
	
	// 清空session
	router.get('/loginOut',login_router());
	
	// 定时任务
	router.get('/startCron',cron_router('start'));
	router.get('/stopCron',cron_router('stop'));
	
	return router;
};

